#pragma once

#include <vector>
#include <list>
using namespace std;

template <class T>
class ArrayOfList {
    private:
        vector< list<T> > *theArray;

        void resize(size_t aSize);
    public:
        ArrayOfList();
        ArrayOfList(const ArrayOfList<T> &anArrayOfList);
        ~ArrayOfList();
        ArrayOfList<T>& operator=(const ArrayOfList<T> &anArrayOfList);
        list<T>& operator[](size_t anIndex);
        size_t size();
};

template <class T>
ArrayOfList<T>::ArrayOfList() {
    this->theArray = new vector< list<T> >;
}

template <class T>
ArrayOfList<T>::ArrayOfList(const ArrayOfList<T> &anArrayOfList) {
    this->theArray = anArrayOfList.theArray;
}

template <class T>
ArrayOfList<T>::~ArrayOfList() {
    delete this->theArray;
}

template <class T>
ArrayOfList<T>& ArrayOfList<T>::operator=(const ArrayOfList<T> &anArrayOfList) {
    if(*this != anArrayOfList) {
        this->theArray = anArrayOfList.theArray;
    }
    return *this;
}

//this will resize the array so that it can always return a list
//theArray is always size n+1
template <class T>
list<T>& ArrayOfList<T>::operator[](size_t anIndex) {
    if( anIndex >= this->theArray->size() ) {
        this->resize( anIndex );
    }
    return this->theArray->at(anIndex);
}

template <class T>
size_t ArrayOfList<T>::size() {
    return this->theArray->size();
}

//Splices the old lists into the new lists to advoid having to copy everything
template <class T>
void ArrayOfList<T>::resize(size_t aSize) {
    vector< list<T> > *newArray = new vector< list<T> >(aSize+1, list<T>());
    for(size_t i = 0; i < this->theArray->size(); i++) {
        typename list<T>::iterator aListIterator = newArray->at(i).begin();
        newArray->at(i).splice(aListIterator, this->theArray->at(i));
    }
    delete this->theArray;
    this->theArray = newArray;
}

